#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <time.h>

#include "sdlNiveau.h"


const int TAILLE_SPRITE_HEROS_X=56;
const int TAILLE_SPRITE_HEROS_Y=49;
const int TAILLE_SPRITE_ENNEMI_X2=40; 
const int TAILLE_SPRITE_ENNEMI_Y2=30;
const int TAILLE_SPRITE_TIR_ENNEMI_X2=15; 
const int TAILLE_SPRITE_TIR_ENNEMI_Y2=19;
const int TAILLE_SPRITE_TIR_ENNEMI_X=10;
const int TAILLE_SPRITE_TIR_ENNEMI_Y=10;
const int TAILLE_SPRITE_BONUS_X=33;
const int TAILLE_SPRITE_BONUS_Y=30;


/** @brief Cette fonction permet charger une image*/
SDL_Surface* SDL_load_image(const char* filename )
{
	SDL_Surface* Image = NULL;
	Image =IMG_Load(filename);
	return Image;
}


/** @brief Cette fonction permet d'integrer des sprites sur l'ecran*/
void SDL_apply_surface( SDL_Surface* source, SDL_Surface* destination, int x, int y )
{
	//on genere une structure temporaire qui contient des coordonnees
	SDL_Rect offset;
	offset.x = x;
	offset.y = y;
	SDL_BlitSurface( source, NULL, destination, &offset );
}


void sdlNiveauInit(sdlNiveau *pSdlNiveau)
{
	Niveau* pniveau;
	pniveau = &(pSdlNiveau->niveau);
	initNiveau(pniveau, niveauGetTerrainPtr(pniveau), niveauGetBossPtr(pniveau), niveauGetHerosPtr(pniveau),
		   pniveau->ptab_pennemis, pniveau->ptab_ptirs, pniveau->ptab_pbonus);
	
	SDL_Init(SDL_INIT_EVERYTHING);
	assert(SDL_Init(SDL_INIT_EVERYTHING) == 0);
	SDL_EnableKeyRepeat(60, 60);     //Active la répétition des touches quand on maintient une touche enfoncée
	
	//TTF permet de simuler l'écriture de texte sous SDL
	TTF_Init();
	if(TTF_Init() == -1)
	{
		fprintf(stderr, "Erreur d'initialisation de TTF_Init : %s\n", TTF_GetError());
		exit(EXIT_FAILURE);
	}
	
	//on charge dans la memoire video c'est plus optimise et plus rapide
	pSdlNiveau->surface_ecran = SDL_SetVideoMode(800, 700, 32, SDL_HWSURFACE | SDL_DOUBLEBUF); // 700 = 600 + texte.
	assert( pSdlNiveau->surface_ecran != NULL); //on s'assure que le chargement se soit bien passe
	SDL_WM_SetCaption("Poireau", NULL );	//on ajoute un titre a la fenètre
	
	//on charge les images du heros etc...
	pSdlNiveau->surface_heros = SDL_load_image("data/hheros2.png");
	if (pSdlNiveau->surface_heros == NULL)
		pSdlNiveau->surface_heros = SDL_load_image("../data/hheros2.png");
	assert( pSdlNiveau->surface_heros != NULL); //on s'assure qu'une image ait été chargée

	pSdlNiveau->surface_boss = SDL_load_image("data/boss.png");
	if (pSdlNiveau->surface_boss == NULL)
		pSdlNiveau->surface_boss = SDL_load_image("../data/boss.png");
	assert( pSdlNiveau->surface_boss != NULL);

	pSdlNiveau->surface_ennemi1 = SDL_load_image("data/ennemi1.png");
	if (pSdlNiveau->surface_ennemi1 == NULL)
		pSdlNiveau->surface_ennemi1 = SDL_load_image("../data/ennemi1.png");
	assert( pSdlNiveau->surface_ennemi1 != NULL);
	
	pSdlNiveau->surface_ennemi2 = SDL_load_image("data/ennemi2.png");
	if (pSdlNiveau->surface_ennemi2 == NULL)
		pSdlNiveau->surface_ennemi2 = SDL_load_image("../data/ennemi2.png");
	assert( pSdlNiveau->surface_ennemi2 != NULL);
	
// 	pSdlNiveau->surface_ennemi4 = SDL_load_image("data/asteroide.png");   //SPRITE asteroide : trouver mieux.
// 	if (pSdlNiveau->surface_ennemi4 == NULL)
// 		pSdlNiveau->surface_ennemi4 = SDL_load_image("../data/asteroide.png");
// 	assert( pSdlNiveau->surface_ennemi4 != NULL);

	pSdlNiveau->surface_tir_ennemi_1 = SDL_load_image("data/tir_ennemi_2.png");
	if (pSdlNiveau->surface_tir_ennemi_1 == NULL)
		pSdlNiveau->surface_tir_ennemi_1 = SDL_load_image("../data/tir_ennemi_2.png");
	assert( pSdlNiveau->surface_tir_ennemi_1 != NULL);

	pSdlNiveau->surface_tir_heros = SDL_load_image("data/tir_heros.png");
	if (pSdlNiveau->surface_tir_heros == NULL)
		pSdlNiveau->surface_tir_heros = SDL_load_image("../data/tir_heros.png");
	assert( pSdlNiveau->surface_tir_heros != NULL);

	pSdlNiveau->surface_tir_heros_S1 = SDL_load_image("data/tir_ennemi_1.png");
	if (pSdlNiveau->surface_tir_heros_S1 == NULL)
		pSdlNiveau->surface_tir_heros_S1 = SDL_load_image("../data/tir_ennemi_1.png");
	assert( pSdlNiveau->surface_tir_heros_S1 != NULL);

	pSdlNiveau->surface_bonus1 = SDL_load_image("data/bonus1.png");
	if (pSdlNiveau->surface_bonus1 == NULL)
		pSdlNiveau->surface_bonus1 = SDL_load_image("../data/bonus1.png");
	assert( pSdlNiveau->surface_bonus1 != NULL);

	pSdlNiveau->surface_bonus2 = SDL_load_image("data/bonus2.png");
	if (pSdlNiveau->surface_bonus1 == NULL)
		pSdlNiveau->surface_bonus1 = SDL_load_image("../data/bonus2.png");
	assert( pSdlNiveau->surface_bonus1 != NULL);

	pSdlNiveau->surface_bonus3 = SDL_load_image("data/bonus3.png");
	if (pSdlNiveau->surface_bonus1 == NULL)
		pSdlNiveau->surface_bonus1 = SDL_load_image("../data/bonus3.png");
	assert( pSdlNiveau->surface_bonus1 != NULL);
	
	pSdlNiveau->surface_poireau = SDL_load_image("data/poireau4.png");
	if (pSdlNiveau->surface_poireau == NULL)
		pSdlNiveau->surface_poireau = SDL_load_image("../data/poireau4.png");
	assert( pSdlNiveau->surface_poireau != NULL);	
}
	
	
void sdlNiveauAff(sdlNiveau *pSdlNiveau)
{
	
	int i_ennemi, i_tir, i_bonus;
	int dimX=800; int dimY=600;

	Niveau* pniveau = &(pSdlNiveau->niveau);
	Heros *phero = niveauGetHerosPtr(pniveau);
	
	SDL_Rect position_texte;
	SDL_Surface* texte_vie = NULL;
	SDL_Surface* texte_score_niv = NULL;
	SDL_Surface* texte_mun1 = NULL;
	SDL_Surface* texte_mun2 = NULL;
	
	SDL_apply_surface(pSdlNiveau->surface_poireau, pSdlNiveau->surface_ecran, 0, 0);
	
	//on attaque la zone SDL_ttf qui permet d inserer du texte 
	TTF_Font *police = NULL;
	police = TTF_OpenFont("../data/alphawood.ttf", 20);  //choix police (fichier .ttf)
	if(!police) 
	{
		printf("TTF_OpenFont: %s\n", TTF_GetError());
		exit(1);
	}
	SDL_Color couleur_texte = {255, 255, 255};
	char vies[20] = {0};
	sprintf(vies, "Vies  %d", getVieHeros(niveauGetConstHerosPtr(pniveau)));  //le resultat de cette fonction est une chaine de caracteres (ici vies)
	texte_vie = TTF_RenderText_Blended(police,vies, couleur_texte); 

	char score_niv[20] = {0};
	sprintf(score_niv, "Score  %d", getScoreNiveau(pniveau)); 
	texte_score_niv = TTF_RenderText_Blended(police, score_niv, couleur_texte); 
	 
	char mun_arm_sc1[10] = {0};
	sprintf(mun_arm_sc1, "Munitions1  %d", getMunitions(getArmeSecondaire1(niveauGetConstHerosPtr(pniveau))));
	texte_mun1 = TTF_RenderText_Blended(police, mun_arm_sc1, couleur_texte);
	 
	char mun_arm_sc2[10] = {0};
	sprintf(mun_arm_sc2, "Munitions2  %d", getMunitions(getArmeSecondaire2(niveauGetConstHerosPtr(pniveau))));
	texte_mun2 = TTF_RenderText_Blended(police, mun_arm_sc2, couleur_texte);
	
	position_texte.x = 10;
        position_texte.y = 610;
        SDL_BlitSurface(texte_vie, NULL, pSdlNiveau->surface_ecran, &position_texte);  //on affiche la chaine de caractere comme une surface
	
	position_texte.x = 200;
        position_texte.y = 610;
        SDL_BlitSurface(texte_score_niv, NULL, pSdlNiveau->surface_ecran, &position_texte);
	
	position_texte.x = 400;
        position_texte.y = 610;
        SDL_BlitSurface(texte_mun1, NULL, pSdlNiveau->surface_ecran, &position_texte); 
	
	position_texte.x = 600;
        position_texte.y = 610;
        SDL_BlitSurface(texte_mun2, NULL, pSdlNiveau->surface_ecran, &position_texte); 
	
	TTF_CloseFont(police);
	
	float coord_debut_fenetre_sdl=(pniveau->posY_debut_fenetre)/150.0*dimY;
	
	for (i_ennemi=0; i_ennemi<getNbreEnnemis(pniveau); i_ennemi++)
	{
		Ennemi *pennemi;
		pennemi = niveauGetEnnemiPtr (pniveau, i_ennemi);
		if (getTypeEnnemiStd(pennemi) == 0)
		{
			  setTailleXEnnemi(pennemi,40.0/8.0);
			  setTailleYEnnemi(pennemi,30.0/4.0);
		}
		else if (getTypeEnnemiStd(pennemi) == 1)
		{
			  setTailleXEnnemi(pennemi,40.0/8.0);
			  setTailleYEnnemi(pennemi,51.0/4.0);
		}

		float coord_abs_posX_ennemi = getPosXEnnemi(pennemi);
		float coord_abs_posY_ennemi = getPosYEnnemi(pennemi)-pniveau->posY_debut_fenetre;
		
		float coord_sdl_posX_ennemi = coord_abs_posX_ennemi/100.0*dimX;
		float coord_sdl_posY_ennemi = coord_abs_posY_ennemi/150.0*dimY;
		
		if (getTypeEnnemiStd(pennemi) == 0)
			SDL_apply_surface(pSdlNiveau->surface_ennemi1, pSdlNiveau->surface_ecran,
					  coord_sdl_posX_ennemi, coord_sdl_posY_ennemi );
			
		else if (getTypeEnnemiStd(pennemi) == 1)
			SDL_apply_surface(pSdlNiveau->surface_ennemi2, pSdlNiveau->surface_ecran,
					  coord_sdl_posX_ennemi, coord_sdl_posY_ennemi );
	}
	setTailleXHeros(phero, 30.0/8.0);
        setTailleYHeros(phero, 26.0/4.0);
		  
	float coord_abs_posX_heros=getPosXHeros(phero);
	float coord_abs_posY_heros=getPosYHeros(phero)-pniveau->posY_debut_fenetre;
		 
	float coord_sdl_posX_heros = coord_abs_posX_heros/100.0*dimX;
	float coord_sdl_posY_heros = coord_abs_posY_heros/150.0*dimY;
    
	// Copier le sprite du heros sur l'écran 
	SDL_apply_surface(pSdlNiveau->surface_heros, 
		  pSdlNiveau->surface_ecran, 
		  coord_sdl_posX_heros, 
		  coord_sdl_posY_heros);
	 if (niveauGetConstBossPtr(pniveau) != NULL)
	 {
		setTailleXBoss(pniveau->pboss, 60.0/8.0);
		setTailleYBoss(pniveau->pboss, 55.0/4.0);
		  
		float coord_abs_posX_boss = getPosXBoss(pniveau->pboss);
		float coord_abs_posY_boss = getPosYBoss(pniveau->pboss)-pniveau->posY_debut_fenetre;
		
		float coord_sdl_posX_boss = coord_abs_posX_boss/100.0*dimX;
		float coord_sdl_posY_boss = coord_abs_posY_boss/150.0*dimY;
		
		  
	SDL_apply_surface(pSdlNiveau->surface_boss, 
		  pSdlNiveau->surface_ecran, 
		  coord_sdl_posX_boss, 
		  coord_sdl_posY_boss);
	 }
			    
	for (i_tir = 0; i_tir < getNbreTirs(pniveau); i_tir++)
	{
		Tir* ptir;
		ptir = niveauGetTirPtr(pniveau, i_tir);
		
		setTailleXTir(ptir,10.0/8.0);
		setTailleYTir(ptir,10.0/4.0);
		
		float coord_abs_posX_tir = getPosXTir(ptir);
		float coord_abs_posY_tir = getPosYTir(ptir) - pniveau->posY_debut_fenetre;
		
		float coord_sdl_posX_tir = coord_abs_posX_tir/100.0*dimX;
		float coord_sdl_posY_tir = coord_abs_posY_tir/150.0*dimY;
		     
		      
		if (ptir->tir_ami == 1) //le tir vient de l'ennemi
		{
				SDL_apply_surface(pSdlNiveau->surface_tir_ennemi_1,
				      pSdlNiveau->surface_ecran, 
				      coord_sdl_posX_tir,
				      coord_sdl_posY_tir );
		}
		
		else  if (ptir->tir_ami == 0) //le tir vient du heros, tir normal
		{
				SDL_apply_surface(pSdlNiveau->surface_tir_heros,
				      pSdlNiveau->surface_ecran, 
				     coord_sdl_posX_tir,
				     coord_sdl_posY_tir);
		}
		else if (ptir->tir_ami == 2) //le tir vient du heros, missile
		{
				SDL_apply_surface(pSdlNiveau->surface_tir_heros_S1,
				      pSdlNiveau->surface_ecran, 
				      coord_sdl_posX_tir,
				      coord_sdl_posY_tir);
		}
		
	}
	for (i_bonus=0; i_bonus < getNbreBonus(pniveau); i_bonus++)
	{
		Bonus *pbonus;
		pbonus = niveauGetBonusPtr (pniveau, i_bonus);
	  
		float coord_abs_posX_bonus = getPosXBonus(pbonus);
		float coord_abs_posY_bonus = getPosYBonus(pbonus);
		
		float coord_sdl_posX_bonus = coord_abs_posX_bonus/100.0*dimX;		
		float coord_sdl_posY_bonus = coord_abs_posY_bonus/150.0*dimY;

		if (getEstBonusArme (pbonus) == 0)
		{
			SDL_apply_surface(pSdlNiveau->surface_bonus1,
			      pSdlNiveau->surface_ecran,
			      coord_sdl_posX_bonus,
			      coord_sdl_posY_bonus - coord_debut_fenetre_sdl);
		}
		else if (getEstBonusArme (pbonus) == 1)
		{
			SDL_apply_surface(pSdlNiveau->surface_bonus2,
			      pSdlNiveau->surface_ecran,
			      coord_sdl_posX_bonus,
			      coord_sdl_posY_bonus - coord_debut_fenetre_sdl);
		}
		else if (getEstBonusArme (pbonus) == 2)
		{
			SDL_apply_surface(pSdlNiveau->surface_bonus3,
			      pSdlNiveau->surface_ecran,
			      coord_sdl_posX_bonus,
			      coord_sdl_posY_bonus - coord_debut_fenetre_sdl);
		}
	}
}


void sdlNiveauBoucle(sdlNiveau *pSdlNiveau)
{	
	SDL_Event event;
	int continue_boucle = 1;

	// Horloges (en secondes) 
	float horloge_courante, horloge_precedente;

	//Intervalle de temps (en secondes) entre deux évolutions du jeu 
	float intervalle_horloge = 0.05f;
	
	int rafraichissement;
	
	sdlNiveauAff(pSdlNiveau);
	
	assert(SDL_Flip(pSdlNiveau->surface_ecran) !=-1);

	// Récupère l'horloge actuelle et la convertit en secondes 
	// clock() retourne le nombre de tops horloge depuis le lancement du programme 
	horloge_precedente = (float)clock()/(float)CLOCKS_PER_SEC;

	while ( continue_boucle == 1 )
	{
		rafraichissement = 0;

		horloge_courante = (float)clock()/(float)CLOCKS_PER_SEC;
    
		
		// Si suffisamment de temps s'est écoulé depuis la dernière prise d'horloge 
		if (horloge_courante-horloge_precedente>=intervalle_horloge)
		{	
			niveauEvolution(&(pSdlNiveau->niveau));
			
			Niveau* pniveau;
			pniveau = &(pSdlNiveau->niveau);
			if (getNumNiveauActuel(pniveau) == getNumNiveauSuivant(pniveau)      //quand le boss est detruit on retourne au menu
				|| getNumNiveauActuel(pniveau) > getNumNiveauSuivant(pniveau))   //quand le heros est detruit on retourne au menu
					continue_boucle = 0;
					rafraichissement = 1;
					horloge_precedente = horloge_courante;
		}
	
		// tant qu'il y a des evenements à traiter : cette boucle n'est pas bloquante 
		while ( SDL_PollEvent( &event ) )
		{
			
			// Si l'utilisateur a cliqué sur la croix de fermeture 
			if ( event.type == SDL_QUIT )
			{
				continue_boucle = 0;
				char pseudo[50];
				chargerNom(pseudo);
				Profil* pprofil = chargerProfil(pseudo); 
				transfererDonneesProfil(pprofil, pseudo, 0, 0, getScoreNiveau(&(pSdlNiveau->niveau)),
					                getDifficulteNiveau(&(pSdlNiveau->niveau)));
				sauvegarderProfil(pprofil);
			}

			// Si l'utilisateur a appuyé sur une touche 
			if ( event.type == SDL_KEYDOWN )
			{
				switch ( event.key.keysym.sym )
				{
				  
				case SDLK_ESCAPE: // Appui sur la touche Echap, on arrête le programme 
					continue_boucle = 0;
					char pseudo[50];
					chargerNom(pseudo);
					Profil* pprofil = chargerProfil(pseudo); 
					transfererDonneesProfil(pprofil, pseudo, 0, 0, getScoreNiveau(&(pSdlNiveau->niveau)),
								getDifficulteNiveau(&(pSdlNiveau->niveau)));
					sauvegarderProfil(pprofil);
					break;
				case SDLK_UP:
					niveauActionClavierSouris( &(pSdlNiveau->niveau), 'h');
					rafraichissement = 1;
					break;
				case SDLK_DOWN:
					niveauActionClavierSouris( &(pSdlNiveau->niveau), 'b');
					rafraichissement = 1;
					break;
				case SDLK_LEFT:
					niveauActionClavierSouris( &(pSdlNiveau->niveau), 'g');
					rafraichissement = 1;
					break;
				case SDLK_RIGHT:
					niveauActionClavierSouris( &(pSdlNiveau->niveau), 'd');
					rafraichissement = 1;
					break;	
				case SDLK_SPACE: 
					niveauActionClavierSouris( &(pSdlNiveau->niveau), 't');
					rafraichissement = 1;
					break;
				case SDLK_LCTRL: 
					niveauActionClavierSouris( &(pSdlNiveau->niveau), 'u');
					rafraichissement = 1;
					break;
				case SDLK_RCTRL: 
					niveauActionClavierSouris( &(pSdlNiveau->niveau), 'v');
					rafraichissement = 1;
					break;
				case SDLK_TAB:
					niveauActionClavierSouris( &(pSdlNiveau->niveau), 'm');
					rafraichissement = 1;
					break;
				case SDLK_BACKSPACE: 
					niveauActionClavierSouris( &(pSdlNiveau->niveau), 'o');
					rafraichissement = 1;
					break;
				default: 
					break;
				}
			}

		}

		if (rafraichissement==1)
		{
			// on affiche le niveau sur le buffer caché 
			sdlNiveauAff(pSdlNiveau);

			// on permute les deux buffers 
			SDL_Flip( pSdlNiveau->surface_ecran );
		}
	}
	SDL_Quit();    //SDL appelle des malloc quand on l'initialise SDL_Quit libère ces malloc
	
}	

